﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Software41.Tracking.Tracing;
using System.Diagnostics;

namespace Software41.Tracking.BAM
{
    [Serializable]
    public class LogDetail
    {
        internal const string LOGDETAIL_ACTIVITY = "LogDetail";
        internal const string LOGDETAIL_ACTIVITY_CREATED_AT = "CreatedAt";
        internal const string LOGDETAIL_ACTIVITY_MSG = "Message";
        internal const string LOGDETAIL_ACTIVITY_TYPE = "Type";
        internal const string LOGDETAIL_ACTIVITY_DATA = "Data";
        internal const string LOGDETAIL_ACTIVITY_DATA_ASSOC_DATA = "AssociatedData";


        public ActivityStateType State { get; private set; }
        public string LogDetailId { get; set; }
        public string Name { get; set; }
        private IEventStream EventStream { get; set; }
        private StringBuilder LogMessage { get; set; }


        public LogDetail(string logDetailId, IEventStream eventStream)
        {
            this.LogDetailId = logDetailId;
            this.LogMessage = new StringBuilder();
            this.EventStream = eventStream;
        }

        public LogDetail(string logDetailId)
            : this(logDetailId, new Adapters.OrchestrationEventStreamAdapter())
        {
        }

        public LogDetail()
            : this(null, new Adapters.OrchestrationEventStreamAdapter())
        {
        }

        #region Begin
        public string Begin(ProcessTraceInfo processInfo)
        {
            if (processInfo == null)
                throw new ArgumentNullException("processInfo");

            this.BeginInternal();
            this.AddRelatedActivity(ActivityType.ProcessTraceInfo.ToString(), processInfo.ProcessInfoId);
            return this.LogDetailId;
        }

        public string Begin(StepInfo stepInfo)
        {
            if (stepInfo == null)
                throw new ArgumentNullException("stepInfo");

            this.BeginInternal();
            this.AddRelatedActivity(ActivityType.StepInfo.ToString(), stepInfo.StepInfoId);
            return this.LogDetailId;
        }

        public string Begin(ActionInfo actionInfo)
        {
            if (actionInfo == null)
                throw new ArgumentNullException("actionInfo");

            this.BeginInternal();
            this.AddRelatedActivity(ActivityType.ActionInfo.ToString(), actionInfo.ActionInfoId);
            return this.LogDetailId;
        }

        private void BeginInternal()
        {
            if (string.IsNullOrEmpty(this.LogDetailId))
                this.LogDetailId = Guid.NewGuid().ToString();

            this.UpdateActivity(LOGDETAIL_ACTIVITY_CREATED_AT, DateTime.UtcNow);
            this.EventStream.BeginActivity(LOGDETAIL_ACTIVITY, this.LogDetailId);
            this.TraceBeginEvent();

            this.State = ActivityStateType.Started;
        }
        #endregion


        public void AddDetail(string detail)
        {
            this.AddDetail(detail, false);
        }

        public void AddDetail(string detail, bool overwriteExisting)
        {

            if (overwriteExisting)
                this.LogMessage = new StringBuilder();

            this.LogMessage.AppendLine(detail);

        }

        //public void AddMessage(string messageDataName, string messageData)
        //{
        //    this.AddRelatedDocument(messageDataName, messageData, LOGDETAIL_ACTIVITY_DATA_ASSOC_DATA);
        //    this.TraceAddMessage(messageDataName, messageData);
        //}


        #region End
        public void End()
        {
            if (this.LogMessage.Length > 0)
                this.UpdateActivity(LOGDETAIL_ACTIVITY_MSG, this.LogMessage.ToString());

            this.EventStream.EndActivity(LOGDETAIL_ACTIVITY, this.LogDetailId);

            this.TraceEndEvent();

            this.State = ActivityStateType.Complete;
        }

        #endregion

        #region Private Helpers
        private void AddRelatedActivity(string relatedActivityName, string releatedActivityInstance)
        {
            this.EventStream.AddRelatedActivity(LOGDETAIL_ACTIVITY, this.LogDetailId,
                                                    relatedActivityName, releatedActivityInstance);
        }

        private void UpdateActivity(string itemName, object itemValue)
        {
            this.EventStream.UpdateActivity(LOGDETAIL_ACTIVITY, this.LogDetailId, itemName, itemValue);
            this.TraceUpdateActivity(itemName, itemValue);
        }

        //private void AddRelatedDocument(string messageDataName, string messageData, string referenceName)
        //{
        //    if ((!string.IsNullOrEmpty(messageDataName)) && (!string.IsNullOrEmpty(messageData)))
        //    {
        //        this.EventStream.AddReference(LOGDETAIL_ACTIVITY, this.DetailInfoId,
        //                                    LOGDETAIL_ACTIVITY_DATA + "-" + referenceName, referenceName,
        //                                    messageDataName, messageData);


        //        var msgDataLink = BAMLinkedDocUrlGenerator.GenerateLinkedDocUrl(LOGDETAIL_ACTIVITY, this.DetailInfoId, LOGDETAIL_ACTIVITY_DATA + "-" + referenceName);

        //        this.EventStream.AddReference(LOGDETAIL_ACTIVITY, this.DetailInfoId,
        //                                        BAMLinkedDocUrlGenerator.BAM_DOCUMENT_URL,
        //                                        messageDataName + " " + referenceName, msgDataLink);

        //    }
        //}

        private void TraceBeginEvent(string messageDataName, string messageData)
        {
            WorkflowProcessTraceSource.TraceEvent(TraceEventType.Verbose, ProcessDiagnosticsEventId.ActionInfoStart,
                            string.Format("Begin DetailInfo Event."));
        }


        private void TraceBeginEvent()
        {
            WorkflowProcessTraceSource.TraceEvent(TraceEventType.Information,
                                                    ProcessDiagnosticsEventId.ExceptionInfoStart,
                                                    "Begin DetailInfo Event.");

        }


        private void TraceEndEvent()
        {
            WorkflowProcessTraceSource.TraceEvent(TraceEventType.Information, 
                                                    ProcessDiagnosticsEventId.StepInfoEnd,
                                                    "End DetailInfo Event.");

        }
        //private void TraceAddMessage(string messageDataName, string messageData)
        //{
        //    WorkflowProcessTraceSource.TraceEvent(TraceEventType.Verbose, ProcessInfoTraceEventId.ActionInfoStart,
        //                   string.Format("Begin DetailInfo Event. DetailInfo.DataName: [{0}], DetailInfo.Data[{1}]",
        //                                       messageDataName, messageData));
        //}

        private void TraceUpdateActivity(string itemName, object itemValue)
        {
            WorkflowProcessTraceSource.TraceEvent(TraceEventType.Information, ProcessDiagnosticsEventId.ActivityUpdated,
                                    string.Format("DetailInfo Update Activity.  DetailInfo.{0} Value: [{1}]", itemName, itemValue));
        }
        #endregion



    }
}
